#include "SLGEngine.h"
#include <boost/timer.hpp>
/*#include "time.h"
#include <boost/bind.hpp>*/

	LPDIRECT3DDEVICE9				g_pd3dDevice=NULL;
	LPDIRECTINPUT8					g_pdInput=NULL;
	FILE* fp=fopen("mouse.log","ab");
	bool g_WindowActive=true;
	/*LPDIRECT3D9             g_pD3D = NULL; // Used to create the D3DDevice
	LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
	LPD3DXLINE				g_line=NULL;
	Texture g_tex;						//Texture manager.
	Error g_err;*/
	SLGEngine::SLGEngine(void)
	{
	}


	SLGEngine::~SLGEngine(void)
	{
		fclose(fp);
	}

	bool SLGEngine::Init()
	{
		if(!InitData())
		{
			return false;
		}

		NewWindow();
		
		if(FAILED(InitD3D()))
			return false;
		if(InitDevice()==false)
			return false;
		
		ShowWindow(m_hWnd, SW_SHOW);
		UpdateWindow(m_hWnd);
		return TRUE;
	}

	bool SLGEngine::InitData()
	{
		m_screenWidth=WIDTH;
		m_screenHeight=HEIGHT;
		Coordinate::Instance(m_screenWidth,m_screenHeight);
		m_objectManager=new ObjectManager;
		m_logic=new LogicEngine(0);
		ObjectId logicId=m_objectManager->createObject();
		m_objectManager->addComponent(logicId,m_logic);
		m_render=new RenderEngine;
		ObjectId renId = m_objectManager->createObject();
		m_objectManager->addComponent(renId,m_render);
		//ObjectId coordId=m_objectManager->createObject();
		//m_objectManager->addComponent(coordId,Coordinate::Instance());
		return true;
	}

	
	bool SLGEngine::InitDevice()
	{
		Mouse* mouse = new Mouse(m_hWnd);
		ObjectId mouseId = m_objectManager->createObject();
		m_objectManager->addComponent(mouseId,mouse);
		KeyBoard* keyboard = new KeyBoard(m_hWnd);
		ObjectId keybId = m_objectManager->createObject();
		m_objectManager->addComponent(keybId,keyboard);
		Resource* res = new Resource();
		ObjectId resId = m_objectManager->createObject();
		m_objectManager->addComponent(resId,res);
		Error* err=new Error();
		ObjectId errId = m_objectManager->createObject();
		m_objectManager->addComponent(errId,err);
		//Camera* cam=new Camera;
		//ObjectId camId=m_objectManager->createObject();
		//m_objectManager->addComponent(camId,cam);
		//ScreenWorld* sw=new ScreenWorld(m_screenWidth,m_screenHeight);
		//ObjectId swId=m_objectManager->createObject();
		//m_objectManager->addComponent(swId,sw);
		m_logic->sendMessage("Init");
		return true;
	}

	void SLGEngine::NewWindow()
	{
		// Register the window class
		WNDCLASSEX wc =
		{
			sizeof( WNDCLASSEX ), CS_CLASSDC, MainWindowProc, 0L, 0L,
			GetModuleHandle( NULL ), NULL, LoadCursor(NULL,IDC_ARROW), NULL, NULL,
			"SLG", NULL
		};
		RegisterClassEx( &wc );

		// Create the application's window
		m_hWnd = CreateWindow( "SLG", "SLG",
			WS_OVERLAPPEDWINDOW, 0, 0, m_screenWidth, m_screenHeight,
			NULL, NULL, wc.hInstance, NULL );
		assert(m_hWnd);
	}

	LRESULT CALLBACK SLGEngine::MainWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		switch( uMsg )
		{
		case WM_DESTROY:
			{
				g_WindowActive=false;
				PostQuitMessage( 0 );
			}
			return 0;
		}

		return DefWindowProc( hWnd, uMsg, wParam, lParam );
	}

	void SLGEngine::GameLoop()
	{
		while(g_WindowActive)
		{
			MSG msg;

			if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
			{
				::TranslateMessage(&msg);
				::DispatchMessage(&msg);
			}
			else
			{
				GameProc();
			}
		}
	}

	void SLGEngine::GameProc()
	{
		DWORD now=GetTickCount();
		m_incTime=now-m_lastTime;
		float t=((float)(m_incTime))/1000;
		if(t<((float)1/FPS))
		{
			Sleep(100);
			return;
		}
		m_lastTime=now;

		UpdateGame();
		GraphRender();
	}

	void SLGEngine::UpdateGame()
	{
		m_logic->Update();
	}

	void SLGEngine::GraphRender()
	{
		m_render->RenderList(m_lastTime);
	}

		//-----------------------------------------------------------------------------
	// Name: InitD3D()
	// Desc: Initializes Direct3D
	//-----------------------------------------------------------------------------
	HRESULT SLGEngine::InitD3D()
	{
		// Create the D3D object.
		if( NULL == ( m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
			return E_FAIL;

		
		m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &m_caps);

		int vp = 0;
		if( m_caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
			vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
		else
			vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

		// Set up the structure used to create the D3DDevice
		assert(m_hWnd);
		D3DPRESENT_PARAMETERS d3dpp;
		ZeroMemory( &d3dpp, sizeof( d3dpp ) );
		d3dpp.BackBufferWidth            =  m_screenWidth;
		d3dpp.BackBufferHeight           = m_screenHeight;
		d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
		d3dpp.BackBufferCount            = 1;
		d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
		d3dpp.MultiSampleQuality         = 0;
		d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
		d3dpp.hDeviceWindow              = m_hWnd;
		d3dpp.Windowed                   = WINDOW;
		d3dpp.EnableAutoDepthStencil     = true; 
		d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
		d3dpp.Flags                      = 0;
		d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;

		// Create the D3DDevice
		if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWnd,vp,&d3dpp, &g_pd3dDevice ) ) )
		{
			if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_SW, m_hWnd,vp,&d3dpp, &g_pd3dDevice ) ) )
			{	
				return E_FAIL;
			}
		}

		m_pD3D->Release();

		if( FAILED(DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION,
			IID_IDirectInput8, ( void** )&g_pdInput, NULL ) ) )
			return E_FAIL;

				g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

	// Turn off D3D lighting
		g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );

	// Turn on the zbuffer
		g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);

	// set blending factors so that alpha component determines transparency
		g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
		g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
		return S_OK;
	}